import {
  ctxDrawCircle, 
  ctxDrawRectangle, 
  ctxDrawLine,
  ctxDrawString,
  ctxDrawTrangle,
} from './ctxDraw';

import { uuid } from './Common';
import { LpDistance } from '../common/Common';

const SIN_60             = Math.sin(Math.PI/3);
const SIN_45             = Math.sin(Math.PI/4);
const SIN_30             = Math.sin(Math.PI/6);

// 2D图形元素基类
class Canava2DItem{
  constructor(name, lineWidth=1, lineStyle=[], fill=false, color=[0,0,0]){
    this.type = name;

    this.lineWidth = lineWidth;
    this.lineStyle = lineStyle;
    this.fill      = fill;
    this.color     = color;

    this.userName  = '';
    this.uuid      = uuid();
  }

  draw(parent){
    this.doDraw(parent.canvas);
  }
  doDraw(){}
}

// 2D点
// x,y 坐标值
// size 大小
// color 颜色
// style 样式 
// 0-实心圆 1-空心圆 2-实心方 3-空心方
// 4-'*' 5-'+' 6-'x' 7 - '-' 8 - '|'
const POINT_TYPE={
  Filled_Circle     :0,
  Circle            :1,
  Filled_Rectangle  :2,
  Rectangle         :3,
  Filled_Trangle    :4,
  Trangle           :5,
  Star              :6,
  Cross             :7,
  X_Cross           :8,
  H_Bar             :9,
  V_Bar             :10,
}

const TREENODE_TYPE={
  Circle : 0,
  Rectangle : 1,
}

class Point2D extends Canava2DItem{
  constructor(x, y, size=1, style=0, color='#000000', lineWidth=1, lineStyle=[]){
    super('Point2D', lineWidth, lineStyle, false, color);
    
    this.centerX = x;
    this.centerY = y;
    this.size    = size;
    this.style   = style;

  }
  
  // 在画布中绘制点
  doDraw(canvas){
    if(!canvas) return;
    const style = this.style;
    const color = this.color;
    const size  = this.size;
    const centerX   = this.centerX;
    const centerY   = this.centerY;
    const lineWidth = this.lineWidth;
    const lineStyle = this.lineStyle;

    if (canvas.getContext){
      var ctx = canvas.getContext('2d');
      switch(style){
        case POINT_TYPE.Filled_Circle: // 实心圆
          ctxDrawCircle(ctx, centerX, centerY, size, true, 0, 360, color, lineWidth, lineStyle);
          break;
        case POINT_TYPE.Circle: // 空心圆
          ctxDrawCircle(ctx, centerX, centerY, size, false, 0, 360, color, lineWidth, lineStyle);
          break;
        case POINT_TYPE.Filled_Rectangle: // 实心方块
          ctxDrawRectangle(ctx, centerX - size, centerY - size, size*2, size*2, true, color, lineWidth, lineStyle);
          break;
        case POINT_TYPE.Rectangle: // 空心方块
          ctxDrawRectangle(ctx, centerX - size, centerY - size, size*2, size*2, false, color, lineWidth, lineStyle);
          break;
        case POINT_TYPE.Filled_Trangle: // 实心三角形
          ctxDrawTrangle(ctx, 
            [centerX - size * SIN_60, centerY + size * SIN_30], 
            [centerX + size * SIN_60, centerY + size * SIN_30], 
            [centerX, centerY - size], 
            true, color, lineWidth, lineStyle);
          break;
        case POINT_TYPE.Trangle: // 空心三角形
          ctxDrawTrangle(ctx, 
            [centerX - size * SIN_60, centerY + size * SIN_30], 
            [centerX + size * SIN_60, centerY + size * SIN_30], 
            [centerX, centerY - size], 
            false, color, lineWidth, lineStyle);
          break;
        case POINT_TYPE.Star: // * 米字型
          ctxDrawLine(ctx, centerX-size*SIN_45, centerY+size*SIN_45, centerX+size*SIN_45, centerY-size*SIN_45, lineWidth, lineStyle, color );
          ctxDrawLine(ctx, centerX-size*SIN_45, centerY-size*SIN_45, centerX+size*SIN_45, centerY+size*SIN_45, lineWidth, lineStyle, color );
          ctxDrawLine(ctx, centerX-size, centerY, centerX+size, centerY, lineWidth, lineStyle, color );
          ctxDrawLine(ctx, centerX, centerY-size, centerX, centerY+size, lineWidth, lineStyle, color );
          break;
        case POINT_TYPE.Cross: // + 十字型
          ctxDrawLine(ctx, centerX-size, centerY, centerX+size, centerY, lineWidth, lineStyle, color );
          ctxDrawLine(ctx, centerX, centerY-size, centerX, centerY+size, lineWidth, lineStyle, color );
          break;
        case POINT_TYPE.X_Cross: // x 叉字型
          ctxDrawLine(ctx, centerX-size*SIN_45, centerY+size*SIN_45, centerX+size*SIN_45, centerY-size*SIN_45, lineWidth, lineStyle, color );
          ctxDrawLine(ctx, centerX-size*SIN_45, centerY-size*SIN_45, centerX+size*SIN_45, centerY+size*SIN_45, lineWidth, lineStyle, color );
          break;
        case POINT_TYPE.V_Bar: // 竖线
          ctxDrawLine(ctx, centerX, centerY-size, centerX, centerY+size, lineWidth, lineStyle, color );
          break;
        case POINT_TYPE.H_Bar: // 横线
          ctxDrawLine(ctx, centerX-size, centerY, centerX+size, centerY, lineWidth, lineStyle, color );
          break;
        default:
          console.error('不支持的点样式');
          break;
      }
    }
  }
}

class FigPoint2D extends Point2D{
  constructor(x, y, size=1, style=0, color='#000000', lineWidth=1, lineStyle=[]){
    super(x, y, size, style, color, lineWidth, lineStyle);

    this.cx = x;
    this.cy = y;
  }

  draw(parent){
    const point = parent.coordinateToPosition(this.cx, this.cy);
    this.centerX = point[0];
    this.centerY = point[1];

    this.doDraw(parent.canvas);
  }
}

class FigCircle extends FigPoint2D{
  constructor(p1, p2, color='#000000', lineWidth=2, lineStyle=[]){
    const r = LpDistance(p1, p2, 2);
    super(p1[0], p1[1], r, POINT_TYPE.Circle, color, lineWidth, lineStyle);

    this.cx2 = p2[0];
    this.cy2 = p2[1];
  }
  draw(parent){
    const point = parent.coordinateToPosition(this.cx, this.cy);
    this.centerX = point[0];
    this.centerY = point[1];
    const point2 = parent.coordinateToPosition(this.cx2, this.cy2);
    
    this.size   = LpDistance(point, point2, 2);
    this.doDraw(parent.canvas);
  }
}

// 两点直线
class Line2D extends Canava2DItem{
  constructor(x1, y1, x2, y2, lineWidth=1, lineStyle=[], color=[0,0,0]){
    super('Line2D');

    this.points    = [[x1, y1], [x2, y2]];
    this.lineWidth = lineWidth;
    this.lineStyle = lineStyle;
    this.color     = color;
  }
  // 在画布中绘制线
  doDraw(canvas){
    if(!canvas) return;
    const points    = this.points;
    const color     = this.color;
    const lineWidth = this.lineWidth;
    const lineStyle = this.lineStyle;

    if (canvas.getContext){
      var ctx = canvas.getContext('2d');
      ctxDrawLine(ctx, points[0][0], points[0][1], points[1][0], points[1][1], lineWidth, lineStyle, color);
    }
  }
}

class FigLine2D extends Line2D{
  constructor(x1, y1, x2, y2, lineWidth=1, lineStyle=[], color=[0,0,0]){
    super(x1, y1, x2, y2, lineWidth, lineStyle, color);

    this.coordinates = [[x1, y1], [x2, y2]];
  }
  draw(parent){
    const point1 = parent.coordinateToPosition(this.coordinates[0][0], this.coordinates[0][1]);
    const point2 = parent.coordinateToPosition(this.coordinates[1][0], this.coordinates[1][1]);
    this.points = [point1, point2];

    this.doDraw(parent.canvas);
  }
}

// 多点组成的路径
class Path2D extends Canava2DItem{
  constructor(points, lineWidth=1, lineStyle=[], fill=false, color=[0,0,0]){
    super('Path2D', lineWidth, lineStyle, fill, color);

    this.points = points;
  }

  doDraw(canvas){
    if(!canvas) return;
    const points    = this.points;
    const color     = this.color;
    const lineWidth = this.lineWidth;
    const lineStyle = this.lineStyle;
    const fill      = this.fill;
    
    if(points.length < 2) return;    

    if (canvas.getContext){
      var ctx = canvas.getContext('2d');
      ctx.strokeStyle = (color instanceof Array)?`rgb(${color[0]}, ${color[1]}, ${color[2]})`:color;
      ctx.fillStyle   = (color instanceof Array)?`rgb(${color[0]}, ${color[1]}, ${color[2]})`:color;
      ctx.lineWidth   = lineWidth;
      ctx.setLineDash(lineStyle);
      ctx.beginPath();
      let pos = points[0];
      ctx.moveTo(pos[0], pos[1]);
      for(var i=1, il=points.length; i < il; i++){
        pos = points[i];
        ctx.lineTo(pos[0], pos[1]);
      }
      if(fill){
        ctx.closePath();
        ctx.fill();
      }
      else{
        ctx.stroke();
      }
    }
  }
}

class FigPath2D extends Path2D{
  constructor(points, lineWidth=1, lineStyle=[], fill=false, color=[0,0,0]){
    super(points, lineWidth, lineStyle, fill, color);

    this.coordinates = points;
    this.points = [];
  }

  draw(parent){
  
    for(var i = 0, il = this.coordinates.length; i < il; i++){
      const point = parent.coordinateToPosition(this.coordinates[i][0], this.coordinates[i][1]);
      this.points[i] = point;
    }

    this.doDraw(parent.canvas);
  }
}

// 字符串
class String2D extends Canava2DItem{
  constructor(str, x, y, font, fontSize, fill=true, color=[0,0,0]){
    super('String2D');

    this.x        = x;
    this.y        = y;
    this.str      = str;
    this.font     = font;
    this.fontSize = fontSize;
    this.color    = color;
    this.fill     = fill;
  }
  doDraw(canvas){
    if(!canvas) return;
    const x   = this.x;
    const y   = this.y;
    const str = this.str;
    if (canvas.getContext){
      var ctx = canvas.getContext('2d');
      ctxDrawString(ctx, str, x, y, this.color, this.font, this.fontSize, this.fill, this.lineWidth, this.lineStyle);
    }
  }
}

class FigString2D extends String2D{
  constructor(str, x, y, font, fontSize, fill=true, color=[0,0,0]){
    super(str, x, y, font, fontSize, fill, color);

    this.cx       = x;
    this.cy       = y;
  }
  draw(parent){
    const point = parent.coordinateToPosition(this.cx, this.cy);
    this.x = point[0];
    this.y = point[1];

    this.doDraw(parent.canvas);
  }
}

class TreeNode extends Canava2DItem{
  constructor(x, y, node, nodeType=0, lineWidth=2, lineStyle=[]){
    super('TreeNode', lineWidth, lineStyle);

    this.x = x;
    this.y = y;
    this.node = node;
    this.nodeType = nodeType
  }
  draw(parent){
    this.size     = parent.nodeSize;
    this.bgColor  = parent.nodeBgColor;
    this.color    = parent.nodeColor;
    this.font     = parent.font;
    this.fontSize = parent.fontSize;

    this.doDraw(parent.canvas);
  }
  doDraw(canvas){
    if(!canvas) return;
    const x       = this.x;
    const y       = this.y;
    const size    = this.size;
    const bgColor = this.bgColor;
    const color   = this.color;
    const str     = this.node;
    const nodeType  = this.nodeType;
    const lineWidth = this.lineWidth;
    const lineStyle = this.lineStyle;

    if (canvas.getContext){
      var ctx = canvas.getContext('2d');

      ctx.font        = `${this.fontSize}px ${this.font}`;
      const w         = ctx.measureText(str).width;

      if(nodeType === TREENODE_TYPE.Circle){
        ctxDrawCircle(ctx, x, y, size, true, 0, Math.PI * 2, bgColor, lineWidth, lineStyle);
        ctxDrawCircle(ctx, x, y, size, false, 0, Math.PI * 2, color, lineWidth, lineStyle);
      }
      else if(nodeType === TREENODE_TYPE.Rectangle){
        ctxDrawRectangle(ctx, x - size, y - size, size * 2, size * 2, true, bgColor, lineWidth, lineStyle);
        ctxDrawRectangle(ctx, x - size, y - size, size * 2, size * 2, false, color, lineWidth, lineStyle);
      }
      else{
        ctxDrawRectangle(ctx, x, y, w + 5, this.fontSize + 5, true, bgColor, lineWidth, lineStyle);
        ctxDrawRectangle(ctx, x, y, w + 5, this.fontSize + 5, false, color, lineWidth, lineStyle);
      }

      ctxDrawString(ctx, 
        str,
        x - (w / 2), y + (this.fontSize / 3), 
        this.color, this.font, this.fontSize, true, lineWidth, lineStyle);
    }
  }
}

class TreeNode_R extends Canava2DItem{
  constructor(x, y, node, lineWidth=2, lineStyle=[]){
    super('TreeNode', lineWidth, lineStyle);

    this.x = x;
    this.y = y;
    this.node = node;
  }
  draw(parent){
    this.size     = parent.nodeSize;
    this.bgColor  = parent.nodeBgColor;
    this.color    = parent.nodeColor;
    this.font     = parent.font;
    this.fontSize = parent.fontSize;

    this.doDraw(parent.canvas);
  }
  doDraw(canvas){
    if(!canvas) return;
    const x       = this.x;
    const y       = this.y;
    const size    = this.size;
    const bgColor = this.bgColor;
    const color   = this.color;
    const str     = this.node;
    if (canvas.getContext){
      var ctx = canvas.getContext('2d');
      ctxDrawRectangle(ctx, x-30, y-23, size*2.5, size*1.8, true, bgColor, this.lineWidth, this.lineStyle);
      ctxDrawRectangle(ctx, x-30, y-23, size*2.5, size*1.8, false, color, this.lineWidth, this.lineStyle);
      
      ctx.font        = `${this.fontSize}px ${this.font}`;
      const w = ctx.measureText(str).width;
      ctxDrawString(ctx, 
        str,
        x - (w / 2), y + (this.fontSize / 3), 
        this.color, this.font, this.fontSize, true, this.lineWidth, this.lineStyle);
    }
  }
}

class TreeLine extends Line2D{
  constructor(x1, y1, x2, y2, lineWidth=2, lineStyle=[], color=[0,0,0]){
    super(x1, y1, x2, y2, lineWidth, lineStyle, color);

    this.name = 'TreeLine';
  }
  draw(parent){
    this.nodeSize = parent.nodeSize;

    this.doDraw(parent.canvas);
  }
  // 在画布中绘制线
  doDraw(canvas){
    if(!canvas) return;
    const points    = this.points;
    const color     = this.color;
    const lineWidth = this.lineWidth;
    const lineStyle = this.lineStyle;
    const nodeSize  = this.nodeSize;

    if (canvas.getContext){
      var ctx = canvas.getContext('2d');
      ctxDrawLine(ctx, points[0][0], points[0][1] + nodeSize, points[1][0], points[1][1] - nodeSize, lineWidth, lineStyle, color);
    }
  }
}

export {Point2D, FigPoint2D, Line2D, FigLine2D, String2D, FigString2D, Path2D, FigPath2D, POINT_TYPE};
export {FigCircle};
export {TreeNode, TreeLine, TreeNode_R, TREENODE_TYPE};

// export default Canava2DItem;